package com.fin.zw.aiqas.service;

import com.fin.zw.aiqas.entity.*;
import com.fin.zw.aiqas.enums.FormulaType;
import com.fin.zw.aiqas.enums.Synchronization;
import com.fin.zw.aiqas.model.request.FormulaRequest;
import com.fin.zw.aiqas.model.request.RuleInfoKeywordRequest;
import com.fin.zw.aiqas.model.response.FormulaResponse;
import com.fin.zw.aiqas.model.session.SessionModel;
import com.fin.zw.aiqas.repository.*;
import com.fin.zw.aiqas.util.BadRequestException;
import com.google.common.collect.Lists;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 质检点信息维护表
 */
@Service("formulaService")
public class FormulaService {

    private final static Logger log = LoggerFactory.getLogger(FormulaService.class);

    @Autowired
    FormulaInfoRepository formulaInfoRepository;

    @Autowired
    KeywordRepository keywordRepository;

    @Autowired
    private ScenesRepository scenesRepository;

    @Autowired
    private RuleInfoRepository ruleInfoRepository;

    @Autowired
    private TemplateInfoRepository templateInfoRepository;


    /**
     * 添加质检点
     */
    @Transactional
    public void addCalculation(RuleInfoKeywordRequest request, SessionModel session) {
        Iterable<FormulaInfo> all = formulaInfoRepository.findAll(QFormulaInfo.formulaInfo.formulaCode.eq(request.getFormulaCode()));
        if (all.iterator().hasNext()) {
            throw new BadRequestException("", "不能出现相同编码的质检点！！！！");
        }
        FormulaInfo formulaInfo = new FormulaInfo();
        BeanUtils.copyProperties(request, formulaInfo);
        Optional<ScenesInfo> optional = scenesRepository.findById(request.getClassifyId());
        if (!optional.isPresent()) throw new BadRequestException("", "质检点的应用场景不存在！");
        ScenesInfo scenesInfo = optional.get();
        formulaInfo.setScenesInfo(scenesInfo);
        formulaInfo.setOperatorId(session.getUserId());
        formulaInfo.setOperatorRealName(session.getUserName());
        formulaInfo.setCreateTime(new Date());
        if (formulaInfo.getFormulaType().equals(FormulaType.SENTENCE)) {
            formulaInfo.setIsSynchronize(Synchronization.NO);
        } else {
            formulaInfo.setIsSynchronize(Synchronization.YES);
        }
        formulaInfo.setFormulaCode(request.getFormulaCode());
        Long ruleKeywordId = formulaInfoRepository.save(formulaInfo).getId();
        if (request.getKeywords() != null) {
            request.getKeywords().forEach(e -> {
                keywordRepository.save(new Keyword(e, ruleKeywordId));
            });
        }
    }



    public Boolean exitByCode(String formulaCode, Long formulaId) {
        QFormulaInfo qFormulaInfo = QFormulaInfo.formulaInfo;
        BooleanBuilder builder = new BooleanBuilder();
        builder.and(qFormulaInfo.formulaCode.eq(formulaCode));
        if (formulaId != null)builder.andNot(qFormulaInfo.id.eq(formulaId));
        Iterable<FormulaInfo> formula = formulaInfoRepository.findAll(builder);
        if (formula.iterator().hasNext()) return true;
        return false;
    }

    /**
     * 修改质检点
     */
    @Transactional
    public void updateCalculation(RuleInfoKeywordRequest request, SessionModel session) {
        if (request.getId() == null) throw new BadRequestException("", "需要修改的数据不存在！！！！");
        ArrayList<FormulaInfo> list = Lists.newArrayList(formulaInfoRepository.findAll(QFormulaInfo.formulaInfo.formulaCode.eq(request.getFormulaCode())));
        list.forEach(e->{
            if(e.getId().longValue()!=request.getId().longValue())throw new BadRequestException("", "不能出现相同编码的质检点！！！！");
        });
        Optional<FormulaInfo> infoOptional = formulaInfoRepository.findById(request.getId());
        if (!infoOptional.isPresent()) {
            throw new BadRequestException("", "修改的质检点信息不存在");
        }
        FormulaInfo formulaInfo = infoOptional.get();
        BeanUtils.copyProperties(request, formulaInfo);
        Optional<ScenesInfo> optional = scenesRepository.findById(request.getClassifyId());
        if (!optional.isPresent()) {
            throw new BadRequestException("", "质检点分类信息不存在！");
        }
        ScenesInfo scenesInfo = optional.get();
        formulaInfo.setScenesInfo(scenesInfo);
        formulaInfo.setUpdateTime(new Date());
        formulaInfo.setUpdateUserId(session.getUserId());
        formulaInfo.setUpdateRealName(session.getUserName());
        if (formulaInfo.getFormulaType().equals(FormulaType.SENTENCE)) {
            formulaInfo.setIsSynchronize(Synchronization.NO);
        } else {
            formulaInfo.setIsSynchronize(Synchronization.YES);
        }
        formulaInfoRepository.save(formulaInfo);
        log.info("删除关键字后重新存储！！！");
        this.deleteKeyword(formulaInfo.getId());
        List<Keyword> keywordList = new ArrayList<>();
        request.getKeywords().forEach(e -> {
            keywordList.add(new Keyword(e, formulaInfo.getId()));
        });
        keywordRepository.saveAll(keywordList);
    }

    /**
     * 删除质检点
     */
    @Transactional
    public void deleteCalculation(long ruleKeywordId) {
        //判断规则中是否使用
        Optional<FormulaInfo> optional = formulaInfoRepository.findById(ruleKeywordId);
        if (!optional.isPresent()) {
            throw new BadRequestException("", "选择删除的质检点信息不存在！");
        }
        FormulaInfo info = optional.get();
        Iterator<RuleInfo> iterator = ruleInfoRepository.findAll(QRuleInfo.ruleInfo.formulaInfos.contains(info)).iterator();
        if (iterator.hasNext()) {
            throw new BadRequestException("", "该质检点存在规则中，不允许删除！");
        }
        Iterator<TemplateInfo> templateInfoIterator = templateInfoRepository.findAll(QTemplateInfo.templateInfo.formulaInfos.contains(info)).iterator();
        if (templateInfoIterator.hasNext()) {
            throw new BadRequestException("", "该质检点已经创建了样本，不允许删除！");
        }
        log.info("删除质检点对应的关键字！！！");
        this.deleteKeyword(ruleKeywordId);
        log.info("删除质检点！！！");
        formulaInfoRepository.delete(info);
    }


    /**
     * 根据质检点ID删除关键词
     */
    private void deleteKeyword(Long ruleKeywordId) {
        QKeyword qKeyword = QKeyword.keyword;
        BooleanBuilder builder = new BooleanBuilder();
        builder.and(qKeyword.keyword_info_id.eq(ruleKeywordId));
        Iterable<Keyword> keyWords = keywordRepository.findAll(builder);
        keywordRepository.deleteAll(keyWords);
    }


    /**
     * 查询质检点
     */
    public Page<FormulaResponse> queryAllCalculation(FormulaRequest request, Pageable pageable) {
        QFormulaInfo qFormulaInfo = QFormulaInfo.formulaInfo;
        BooleanBuilder builder = new BooleanBuilder();
        if (StringUtils.isNotBlank(request.getFormulaName()))
            builder.and(qFormulaInfo.name.like("%" + request.getFormulaName() + "%"));
        if (request.getIsSynchronize() != null)
            builder.and(qFormulaInfo.isSynchronize.eq(request.getIsSynchronize()));
        if (request.getFormulaType() != null)
            builder.and(qFormulaInfo.formulaType.eq(request.getFormulaType()));
        if (request.getScenesId() != null)
            builder.and(qFormulaInfo.scenesInfo.id.eq(request.getScenesId()));
        if (request.getFormulaCode() != null)
            builder.and(qFormulaInfo.formulaCode.like("%".concat(request.getFormulaCode()).concat("%")));
        Page<FormulaInfo> detailPage = formulaInfoRepository.findAll(builder, pageable);
        QKeyword qKeyword = QKeyword.keyword;
        Page<FormulaResponse> response = detailPage.map(kw -> {
            FormulaResponse formulaResponse = new FormulaResponse();
            ArrayList<Keyword> kwList = Lists.newArrayList(keywordRepository.findAll(qKeyword.keyword_info_id.eq(kw.getId())));
            Set<String> keyword = kwList.stream().map(Keyword::getName).collect(Collectors.toSet());
            BeanUtils.copyProperties(kw, formulaResponse);
            formulaResponse.setKeywords(keyword);
            return formulaResponse;
        });
        return response;
    }

    /**
     * 查询所有的质检点信息
     * @return
     */
    public List<FormulaResponse> getAllCalculation(FormulaRequest request) {
        QFormulaInfo qFormula = QFormulaInfo.formulaInfo;
        BooleanBuilder builder = new BooleanBuilder();
        if (StringUtils.isNotBlank(request.getFormulaName()))
            builder.and(qFormula.name.like("%" + request.getFormulaName() + "%"));
        if (request.getFormulaType() != null)
            builder.and(qFormula.formulaType.eq(request.getFormulaType()));
        if (request.getScenesId() != null)
            builder.and(qFormula.scenesInfo.id.eq(request.getScenesId()));
        Iterable<FormulaInfo> iterable = formulaInfoRepository.findAll(builder);
        ArrayList<FormulaInfo> rule = Lists.newArrayList(iterable);
        QKeyword qKeyword = QKeyword.keyword;
        List<FormulaResponse> list = rule.stream().map(kw -> {
                    BooleanBuilder kwBuilder = new BooleanBuilder();
                    kwBuilder.and(qKeyword.keyword_info_id.eq(kw.getId()));
                    ArrayList<Keyword> kwList = Lists.newArrayList(keywordRepository.findAll(kwBuilder));
                    Set<String> keyword = kwList.stream().map(Keyword::getName).collect(Collectors.toSet());
                    FormulaResponse formulaResponse = new FormulaResponse();
                    BeanUtils.copyProperties(kw, formulaResponse);
                    formulaResponse.setKeywords(keyword);
                    return formulaResponse;
                }
        ).collect(Collectors.toList());
        return list;
    }

    /**
     * 根据质检点唯一编码查询质检点
     *
     * @param formulaCode
     */
    public FormulaInfo getFormula(String formulaCode) {
        FormulaInfo formulaInfo = formulaInfoRepository.findOne(QFormulaInfo.formulaInfo.formulaCode.eq(formulaCode)).orElseThrow(() -> new BadRequestException("", "根据质检点唯一编码没有查询到质检点"));
        return formulaInfo;
    }

}
